<template>
  <div class="app-container workday-container">
    <div class="button-group">
      <div class="select-date">
        <el-date-picker
          v-model="month"
          type="month"
          placeholder="选择月份"
          class="select-date-year"
          @change="onMonthChange"
        />
      </div>
      <el-button type="primary" @click="daySelectHandle">
        {{ isMultiSelect ? "取消多选" : "多选" }}
      </el-button>
      <el-button type="primary" v-if="isMultiSelect" @click="onHolidaySwitch">
        假日切换
      </el-button>
      <el-button
        type="primary"
        icon="el-icon-setting"
        @click="initWorkDayModalVisible = true"
      >
        初始化数据
      </el-button>
      <el-button
        type="primary"
        icon="el-icon-plus"
        @click="addWorkDayActivityHandle"
      >
        新建活动
      </el-button>
    </div>

    <FullCalendar ref="fullCalendarRef" :options="calendarOptions">
      <template #dayCellContent="content">
        <div class="day-content">
          <div>
            <span class="select-tag" v-if="isShowSelectTag(content)">✔️</span>
            <span class="day-content-left">
              {{ dayNumberTextHandle(content.dayNumberText) }}
            </span>
            <span
              v-if="isWorkDayHandle(content) !== 'uninitialized'"
              class="day-content-right"
              :style="isWorkDayHandle(content) ? '' : 'color: #09d09e'"
            >
              {{ isWorkDayHandle(content) ? "班" : "休" }}
            </span>
          </div>
          <el-tooltip
            effect="dark"
            :content="findDayDesc(content)"
            placement="top"
          >
            <span class="day-desc">
              {{ findDayDesc(content) }}
            </span>
          </el-tooltip>
        </div>
      </template>
      <template #eventContent="content">
        <el-tooltip
          effect="dark"
          :content="content.event.title"
          placement="top"
        >
          <div class="event-content">
            <i class="el-icon-bell" style="margin: 0px 5px" />
            <b>{{ content.event.title }}</b>
          </div>
        </el-tooltip>
      </template>
    </FullCalendar>

    <vxe-modal
      ref="xModal"
      v-model="activityModalVisible"
      class="activity-modal"
      :resize="true"
      width="600"
      height="350"
      :title="activityModalTitle"
      show-zoom
      destroy-on-close
      :show-footer="true"
      :loading="activityModalLoading"
      @close="activityModalClose"
    >
      <el-tabs v-model="activeName" @tab-click="handleTabClick">
        <el-tab-pane label="活动" name="activityTab">
          <el-form
            ref="activityFormRef"
            :model="activityForm"
            :rules="activityRules"
            label-width="100px"
            :disabled="activityFormDisabled"
          >
            <el-form-item prop="title" label="活动名称">
              <el-input v-model="activityForm.title" clearable />
            </el-form-item>
            <el-form-item label="活动时间" required>
              <el-col :span="11">
                <el-form-item prop="start">
                  <el-date-picker
                    v-model="activityForm.start"
                    type="datetime"
                    placeholder="选择开始时间"
                    clearable
                    value-format="yyyy-MM-dd HH:mm:ss"
                  />
                </el-form-item>
              </el-col>
              <el-col class="date-picker-line" :span="2">-</el-col>
              <el-col :span="11">
                <el-form-item prop="end">
                  <el-date-picker
                    v-model="activityForm.end"
                    type="datetime"
                    placeholder="选择结束时间"
                    value-format="yyyy-MM-dd HH:mm:ss"
                    clearable
                  />
                </el-form-item>
              </el-col>
            </el-form-item>
            <el-form-item
              prop="autoWorkload"
              label="是否自动填写工作量"
              label-width="140px"
            >
              <el-switch v-model="activityForm.autoWorkload" />
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane
          v-if="findHolidayDisabled()"
          label="假日切换"
          name="holidayTab"
        >
          <el-form
            ref="switchHolidyFormRef"
            :model="switchHolidyForm"
            :rules="switchHolidyFormRules"
            label-width="80px"
          >
            <el-form-item prop="description" label="描述">
              <el-input
                v-model="switchHolidyForm.description"
                type="textarea"
                :rows="3"
                clearable
              />
            </el-form-item>
          </el-form>
        </el-tab-pane>
      </el-tabs>

      <template #footer>
        <el-button v-if="isHolidayTab" type="primary" @click="switchHoliday">
          切换为{{ selectDayIsWorkDay ? "节假日" : "工作日" }}
        </el-button>
        <template v-if="!isHolidayTab">
          <el-button
            v-if="activityFormDisabled"
            type="primary"
            @click="activityDel"
          >
            删 除
          </el-button>
          <el-button
            v-if="activityFormDisabled"
            type="primary"
            @click="activityEdit"
          >
            编 辑
          </el-button>
          <el-button
            v-if="!activityFormDisabled"
            type="primary"
            @click="activitySubmitForm"
          >
            保 存
          </el-button>
        </template>
        <el-button @click="activityModalCancel">
          取 消
        </el-button>
      </template>
    </vxe-modal>

    <vxe-modal
      ref="initWorkDayRef"
      v-model="initWorkDayModalVisible"
      :resize="true"
      width="300"
      height="200"
      title="提示"
      show-zoom
      show-close
      destroy-on-close
      :show-footer="true"
      :before-hide-method="onBeforeHideMethod"
    >
      <el-date-picker
        v-model="year"
        type="year"
        placeholder="选择年份"
        value-format="yyyy"
      />
      <template #footer>
        <el-button type="primary" @click="initWordDayData">
          确 定
        </el-button>
      </template>
    </vxe-modal>
  </div>
</template>

<script>
import FullCalendar from "@fullcalendar/vue";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import interactionPlugin from "@fullcalendar/interaction";
import listPlugin from "@fullcalendar/list";
import zhCn from "@fullcalendar/core/locales/zh-cn";
import request from "@/utils/request";

export default {
  components: {
    FullCalendar
  },
  filters: {},
  data() {
    return {
      activeName: "activityTab",
      year: new Date(),
      month: new Date(),
      activityModalLoading: false,
      activityModalVisible: false,
      activityModalTitle: "",
      activityFormDisabled: false,
      isAddOperate: false,
      startTime: undefined,
      endTime: undefined,
      workDayData: [],
      isShowHolidaySwitch: false,
      selectDayIsWorkDay: false,
      isHolidayTab: false,
      dateSelectInfo: {
        date: undefined,
        isWorkDay: undefined,
        description: undefined
      },
      switchHolidyForm: {
        description: undefined,
        date: undefined,
        isWorkDay: undefined
      },
      switchHolidyFormRules: {
        description: [
          {
            required: true,
            message: "请填写描述",
            trigger: "blur"
          }
        ]
      },
      activityForm: {
        title: undefined,
        start: undefined,
        end: undefined,
        autoWorkload: true
      },
      activityRules: {
        title: [{ required: true, message: "请填写活动名称", trigger: "blur" }],
        start: [
          { required: true, message: "请选择开始时间", trigger: "change" }
        ],
        end: [{ required: true, message: "请选择结束时间", trigger: "change" }]
      },
      calendarOptions: {
        plugins: [
          dayGridPlugin,
          timeGridPlugin,
          listPlugin,
          interactionPlugin // needed for dateClick
        ],
        events: async (event, callback) => {
          this.startTime = window.formatter.formatDateTime(event.startStr);
          this.endTime = window.formatter.formatDateTime(event.endStr);
          await this.loadData();
          callback([]);
        },
        headerToolbar: {
          left: "prev,next today",
          center: "title",
          right: ""
        },
        dayMaxEventRows: true, // 开启设置最大视图条数
        views: {
          timeGrid: {
            dayMaxEventRows: 6 // adjust to 6 only for timeGridWeek/timeGridDay
          },
          dayGridMonth: {
            displayEventTime: true
          }
        },
        firstDay: 0, // 设置一周中显示的第一天是哪天，周日是0，周一是1，类推
        weekNumbers: false, // 是否在日历中显示周次(一年中的第几周)，如果设置为true，则会在月视图的左侧、周视图和日视图的左上角显示周数。
        aspectRatio: 1.35, // 设置日历单元格宽度与高度的比例。
        handleWindowResize: true, // 是否随浏览器窗口大小变化而自动变化。
        nowIndicator: true, // 周/日视图中显示今天当前时间点（以红线标记），默认false不显示
        navLinks: true, // 当前周是否可以被点击，默认false，如果为true则周视图“周几”被点击之后进入日视图。
        defaultAllDayEventDuration: { days: 1 }, // 默认1天是多长，（有的是采用工作时间模式，所以支持自定义）
        eventColor: "#3BB2E3", // 全部日历日程背景色
        themeSystem: "bootstrap", // 主题色(本地测试未能生效)
        initialView: "dayGridMonth",
        editable: false,
        selectable: true,
        selectMirror: true,
        dayMaxEvents: true,
        weekends: true,
        select: this.handleDateSelect,
        eventClick: this.handleEventClick,
        datesSet: this.handleDatesSet,
        locale: zhCn
      },
      isMultiSelect: false,
      selectDays: new Set(),
      initWorkDayModalVisible: false
    };
  },
  methods: {
    async onMonthChange(month) {
      if (month) {
        this.gotoDateFullCalendar(month);
      }
    },
    gotoDateFullCalendar(date) {
      this.$refs["fullCalendarRef"]
        .getApi()
        .gotoDate(window.formatter.formatDate(date, "yyyy-MM"));
    },
    onHolidaySwitch() {
      const selectDaysSize = this.selectDays.size;
      if (!selectDaysSize > 0) {
        this.$message.info("请选择日期");
        return;
      }
      let workDayCount = 0;
      let holidayCount = 0;
      let isWorkDay;
      const switchHolidayParams = [];
      for (let item of this.workDayData) {
        if (
          this.selectDays.has(window.formatter.formatStartDateTime(item.date))
        ) {
          let workDay = Object.assign({}, item);
          isWorkDay = item.isWorkDay;
          if (item.isWorkDay) {
            workDayCount++;
          } else {
            holidayCount++;
          }
          workDay.isWorkDay = !workDay.isWorkDay;
          switchHolidayParams.push(workDay);
        }
      }
      if (selectDaysSize == workDayCount || selectDaysSize == holidayCount) {
        this.executeSwitchHoliday(isWorkDay, switchHolidayParams);
      } else {
        this.$message.info("请选择同类型日期");
      }
    },
    isShowSelectTag(content) {
      const date = window.formatter.formatDate(content.date);
      return this.selectDays.has(date) ? true : false;
    },
    // 多选控制器
    daySelectHandle() {
      if (this.isMultiSelect) {
        this.selectDays = new Set();
        this.gotoDateFullCalendar(
          window.formatter.formatDate(
            this.$refs["fullCalendarRef"].getApi().getDate(),
            "yyyy-MM"
          )
        );
      }
      this.isMultiSelect = !this.isMultiSelect;
    },
    handleDatesSet(event) {
      const dataSetStartTime = window.formatter.formatDateTime(event.startStr);
      const dataSetEndTime = window.formatter.formatDateTime(event.endStr);
      if (
        dataSetStartTime !== window.formatter.formatDateTime(this.startTime) ||
        dataSetEndTime !== window.formatter.formatDateTime(this.endTime)
      ) {
        this.startTime = dataSetStartTime;
        this.endTime = dataSetEndTime;
        this.loadData();
      }
    },
    dayNumberTextHandle(text) {
      return text.substring(0, text.length - 1);
    },
    isWorkDayHandle(content) {
      let find = false;
      if (this.workDayData.length < 7) {
        return "uninitialized";
      } else {
        find = this.workDayData.find(i => {
          return (
            i.isWorkDay &&
            window.formatter.formatStartDateTime(i.date) ===
              window.formatter.formatStartDateTime(content.date)
          );
        });
      }
      return find;
    },
    async loadData() {
      let loading = this.appLoading("数据加载中...");
      try {
        const res = await request({
          url: "/admin/sysWorkDay/workDayList",
          method: "post",
          headers: { "Content-Type": "application/json" },
          data: {
            start: this.startTime,
            end: this.endTime
          }
        });
        if (res && res.success && res.parameters) {
          const { data } = res.parameters;
          if (Array.isArray(data) && data.length > 0) {
            this.workDayData = data;
            const findData = data.filter(item => {
              return item.activityId;
            });
            const obj = [];
            const validData = findData.reduce((cur, next) => {
              obj[next.activityId]
                ? ""
                : (obj[next.activityId] = true && cur.push(next));
              return cur;
            }, []);
            this.$refs["fullCalendarRef"].options.events = validData;
          }
        } else {
          this.workDayData = [];
          this.$refs["fullCalendarRef"].options.events = [];
          this.$message.error(res.message || "加载数据失败");
        }
      } catch (err) {
        this.$message.error(err.message);
      } finally {
        loading.close();
      }
    },
    handleDateSelect(selectInfo) {
      const { startStr, start, view } = selectInfo;
      if (this.isMultiSelect) {
        if (!this.selectDays.has(startStr)) {
          this.selectDays.add(startStr);
        } else {
          this.selectDays.delete(startStr);
        }
        this.gotoDateFullCalendar(
          window.formatter.formatDate(
            this.$refs["fullCalendarRef"].getApi().getDate(),
            "yyyy-MM"
          )
        );
      } else {
        this.isAddOperate = false;
        const findData = this.workDayData.filter(item => {
          return (
            window.formatter.formatStartDateTime(item.date) ===
            window.formatter.formatStartDateTime(startStr)
          );
        });
        let description;
        if (Array.isArray(findData) && findData.length > 0) {
          this.selectDayIsWorkDay = findData[0].isWorkDay;
          description = findData[0].description;
        }
        this.dateSelectInfo = {
          date: start,
          isWorkDay: this.selectDayIsWorkDay,
          description: description
        };
        if (view.type === "dayGridMonth") {
          this.isShowHolidaySwitch = true;
          this.addWorkDayActivity();
        }
      }
    },
    handleEventClick(clickInfo) {
      if (
        clickInfo &&
        clickInfo.event &&
        clickInfo.event._def &&
        clickInfo.event._def.extendedProps
      ) {
        this.isShowHolidaySwitch = true;
        const {
          isWorkDay,
          activityId,
          description
        } = clickInfo.event._def.extendedProps;
        this.selectDayIsWorkDay = isWorkDay;
        this.dateSelectInfo = {
          date: window.formatter.formatStartDateTime(clickInfo.event.startStr),
          isWorkDay: isWorkDay,
          description: description
        };
        if (activityId) {
          this.isAddOperate = false;
          request({
            url: "/admin/sysWorkDay/getWorkDayActivity",
            method: "get",
            params: {
              activityId: activityId
            }
          })
            .then(r => {
              if (r && r.success && r.parameters) {
                this.activityModalTitle = "假日管理";
                this.activityFormDisabled = true;
                this.activityForm = r.parameters.data;
                this.activityModalVisible = true;
              } else {
                this.$message.error(r.message || "加载数据失败");
              }
            })
            .catch(e => {
              this.$message.error(e);
            });
        } else {
          this.isAddOperate = true;
          this.addWorkDayActivity();
        }
      }
    },
    onBeforeHideMethod() {
      this.year = new Date();
    },
    initWordDayData() {
      const year = window.formatter.formatDate(this.year, "yyyy");
      if (year) {
        this.$confirm('确定初始化"' + year + '"年度日历吗？', "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(async () => {
          try {
            const res = await request({
              url: "/admin/sysWorkDay/initDate",
              method: "POST",
              data: { year: year }
            });
            if (res && res.success) {
              this.$message.success("初始化成功");
              this.loadData();
              this.initWorkDayModalVisible = false;
            } else {
              this.$message.error(res.message || "初始化失败");
            }
          } catch (error) {
            this.$message.error("初始化失败");
          }
        });
      } else {
        this.$message.info("请选择需要初始化的年份");
        return new Error();
      }
    },
    addWorkDayActivityHandle() {
      this.isShowHolidaySwitch = false;
      this.addWorkDayActivity();
    },
    addWorkDayActivity() {
      this.activityFormDisabled = false;
      this.isAddOperate = true;
      this.activityModalTitle = "假日管理";
      this.activityModalVisible = true;
    },
    activitySubmitForm() {
      this.$refs["activityFormRef"].validate(valid => {
        if (valid) {
          this.activityModalLoading = true;
          let url = "/admin/sysWorkDay/updateWorkDayActivity";
          let messagePrefix = "修改";
          if (this.isAddOperate) {
            url = "/admin/sysWorkDay/saveWorkDayActivity";
            messagePrefix = "新建";
          }
          request({
            url: url,
            method: "POST",
            data: this.activityForm,
            headers: { "Content-Type": "application/json" }
          })
            .then(res => {
              if (res.success) {
                this.$message.success(messagePrefix + "活动成功");
                this.resetActivityModalData();
                this.loadData();
                this.activityModalVisible = false;
                this.isHolidayTab = false;
              } else {
                this.$message.error(res.message || messagePrefix + "活动失败");
              }
            })
            .catch(err => {
              this.$message.error(err.message || messagePrefix + "活动失败");
            })
            .finally(() => {
              this.activityModalLoading = false;
            });
        }
      });
    },
    activityEdit() {
      this.activityFormDisabled = false;
      this.activityModalTitle = "假日管理";
    },
    activityDel() {
      const { activityId, title } = this.activityForm;
      this.$confirm('确定要删除活动名称为"' + title + '"的数据吗？', "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          request({
            url: "/admin/sysWorkDay/delWorkDayActivity",
            method: "POST",
            data: { activityId: activityId }
          })
            .then(r => {
              this.$message.success("删除成功");
              this.resetActivityModalData();
              this.loadData();
              this.activityModalLoading = false;
              this.activityModalVisible = false;
            })
            .catch(err => {
              this.activityModalLoading = false;
              this.$message.error(err.message || "删除失败");
            });
        })
        .catch(() => {});
    },
    resetActivityModalData() {
      this.isHolidayTab = false;
      this.activeName = "activityTab";
      this.activityForm = {
        title: undefined,
        start: undefined,
        end: undefined,
        autoWorkload: true
      };
      this.dateSelectInfo = {
        date: undefined,
        isWorkDay: undefined,
        description: undefined
      };
      this.switchHolidyForm = {
        description: undefined,
        date: undefined,
        isWorkDay: undefined
      };
    },
    activityModalClose() {
      this.resetActivityModalData();
    },
    activityModalCancel() {
      this.activityModalVisible = false;
      this.resetActivityModalData();
    },
    switchHoliday() {
      this.$refs["switchHolidyFormRef"].validate(valid => {
        if (valid) {
          this.executeSwitchHoliday(this.selectDayIsWorkDay);
        }
      });
    },
    executeSwitchHoliday(
      selectDayIsWorkDay = this.selectDayIsWorkDay,
      multiSelectSwitchHolidayParams
    ) {
      this.$confirm(
        "是否切换为" + (selectDayIsWorkDay ? "节假日" : "工作日"),
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(() => {
          request({
            headers: { "Content-Type": "application/json" },
            url: "/admin/sysWorkDay/switchHoliday",
            method: "post",
            data: this.buildSwitchHolidayParam(multiSelectSwitchHolidayParams)
          })
            .then(res => {
              if (res.success) {
                this.$message.success(
                  "切换" + (selectDayIsWorkDay ? "节假日" : "工作日") + "成功"
                );
                this.resetMultiSelectTag();
                this.resetActivityModalData();
                this.loadData();
                this.activityModalVisible = false;
              } else {
                this.$message.error(
                  res.message ||
                    "切换" + (selectDayIsWorkDay ? "节假日" : "工作日") + "失败"
                );
              }
            })
            .catch(err => {
              this.$message.error(
                err.message ||
                  "切换" + (selectDayIsWorkDay ? "节假日" : "工作日") + "失败"
              );
            })
            .finally(() => {
              this.activityModalLoading = false;
            });
        })
        .catch(() => {});
    },
    resetMultiSelectTag() {
      if (this.isMultiSelect) {
        this.selectDays = new Set();
      }
    },
    buildSwitchHolidayParam(selectDays) {
      if (!this.isMultiSelect) {
        const switchHolidyForm = Object.assign({}, this.switchHolidyForm);
        switchHolidyForm.date = window.formatter.formatDateTime(
          switchHolidyForm.date
        );
        switchHolidyForm.isWorkDay = !switchHolidyForm.isWorkDay;
        return [switchHolidyForm];
      } else {
        return selectDays;
      }
    },
    handleTabClick(tab, event) {
      const { name } = tab;
      if (name === "holidayTab") {
        Object.assign(this.switchHolidyForm, this.dateSelectInfo);
        this.isHolidayTab = true;
      } else {
        this.isHolidayTab = false;
      }
    },
    findHolidayDisabled() {
      // 日期含有活动项，不允许进行工作日/节假日互转'
      const findData = this.workDayData.filter(item => {
        return (
          window.formatter.formatStartDateTime(item.date) ===
            window.formatter.formatStartDateTime(this.dateSelectInfo.date) &&
          item.activityId
        );
      });
      if (Array.isArray(findData) && findData.length > 0) {
        return false;
      }
      return this.isShowHolidaySwitch;
    },
    findDayDesc(content) {
      const findData = this.workDayData.filter(item => {
        return (
          window.formatter.formatStartDateTime(item.date) ===
          window.formatter.formatStartDateTime(content.date)
        );
      });
      if (Array.isArray(findData) && findData.length > 0) {
        return findData[0].description;
      }
      return "";
    }
  }
};
</script>

<style lang="scss">
.workday-container {
  .button-group {
    width: 100%;
    display: flex;
    flex-flow: row nowrap;
    padding-bottom: 20px;
    .select-date {
      flex: 1;
      .select-date-year {
        width: 120px;
        margin-right: 15px;
      }
    }
  }
  .information-content {
    font-size: 14px;
    width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .date-picker-line {
    text-align: center;
  }
  .activity-modal {
    .el-form {
      .el-form-item {
        .el-form-item__content {
          .el-form-item__error {
            padding-top: 8px;
            line-height: 0;
          }
        }
      }
    }
  }
  .day-content {
    height: 40px;
    z-index: 5;
    cursor: pointer;
    margin: 2px 0px;
    width: 100%;
    text-align: center;
    display: flex;
    flex-flow: column nowrap;
    .select-tag {
      position: absolute;
      left: 6px;
      padding-top: 6px;
    }
    .day-content-left {
      font-size: 20px;
      padding-right: 2px;
      font-weight: bold;
    }
    .day-content-right {
      font-weight: bold;
      padding-top: 6px;
      color: #aaa;
    }
    .day-desc {
      width: 100%;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      color: #aaa;
    }
  }
  .event-content {
    width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .fc .fc-daygrid-day-number {
    padding: 0px;
    display: none;
  }
}
</style>
